/*
 * MPI.h
 *
 *  Created on: Dec 12, 2009
 *      Author: fernandes
 */

#ifndef MPI_H_
#define MPI_H_

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Instruction.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Type.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

BasicBlockPass *createMPIBlock2NonBlockPass();
extern const PassInfo *const MPIBlock2NonBlockID;

ModulePass *createMPIAnnotateFunctionsPass();
extern const PassInfo *const MPIAnnotateFunctionsID;

FunctionPass *createMPIAliasAnalysisPass();
extern const PassInfo *const MPIAliasAnalysisID;

FunctionPass *createMPIOverlapWindowExpansionPass();

struct MPIArgs {
  enum IArgs {
    IBuf = 0, ICount = 1, IDatatype = 2, ISource = 3, ITag = 4, IComm = 5,
    IRequest = 6, EndIArgs
  };

  enum WaitArgs { WaitRequest = 0, WaitStatus = 1, EndWaitArgs };
};

struct MPIConstants {
  static const int ANY_TAG = -1;
  static const int ANY_SOURCE = -1;
  static const int PROC_NULL = -2;
};

struct MPISupport {
private:
  static const Value *getUnderlyingPointer(const Value *V) {
    //errs() << "Pointer is:\n";
    //V->dump();
    //errs() << "---\n";
    //errs().flush();
    if(const Instruction *I = dyn_cast<Instruction>(V)) {
      switch (I->getOpcode()) {
      case Instruction::Load:   return I->getOperand(0);
      case Instruction::Store:  return I->getOperand(1);
      case Instruction::Alloca:  return I;
      case Instruction::BitCast:  return I->getOperand(0);
      default:                  assert(0 && "Unknown instruction (for now)");
      }
    }
    return V;
  }

public:
  static const Value *getPointerArg(const ImmutableCallSite &CS, unsigned Arg) {
    return getUnderlyingPointer(CS.getArgument(Arg));
  }

  static bool verifyIrecvSignature(const FunctionType *FT, LLVMContext *Context) {
    if (FT->getNumParams() != MPIArgs::EndIArgs ||
        FT->getReturnType() != Type::getInt32Ty(*Context) ||
        FT->getParamType(MPIArgs::IBuf) != Type::getInt8PtrTy(*Context) ||
        !isa<IntegerType>(FT->getParamType(MPIArgs::ICount)) ||
        !isa<IntegerType>(FT->getParamType(MPIArgs::ISource)) ||
        !isa<IntegerType>(FT->getParamType(MPIArgs::ITag)) ||
        !isa<PointerType>(FT->getParamType(MPIArgs::IRequest)) )
      return false;
    return true;
  }

  static bool verifyIsendSignature(const FunctionType *FT, LLVMContext *Context) {
    return verifyIrecvSignature(FT, Context);
  }

  static bool verifyWaitSignature(const FunctionType *FT, LLVMContext *Context) {
    if (FT->getNumParams() != MPIArgs::EndWaitArgs ||
        FT->getReturnType() != Type::getInt32Ty(*Context) ||
        !isa<PointerType>(FT->getParamType(MPIArgs::WaitRequest)) ||
        !isa<PointerType>(FT->getParamType(MPIArgs::WaitStatus)) )
      return false;
    return true;
  }

  static AliasAnalysis *MPIAA;
};
#endif /* MPI_H_ */
